package utils;



import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;

public class ConnectionPool {
    //提供静态的私有的本类对象
    private static ConnectionPool pool;
    //构造方法私有化
    private ConnectionPool(){
        init();
    }

    //提供静态的可以获取本类对象的方法
    public static synchronized ConnectionPool getPool(){
        if(pool==null){
            pool = new ConnectionPool();
        }
        return pool;
    }

    public static void main(String[] args) {
        ConnectionPool.getPool().init();
    }

    /**
     * 成员属性
     */
    //数据库连接属性
    private static String driverClass;
    private static String userName;
    private static String password;
    private static String url;
    //初始连接数量
    private static int initCount = 5;
    //最小连接数量
    private static int minCount = 5;
    //最大连接数量
    private static int maxCount = 10;
    //连接数量
    private static int count;
    //存储连接
    private LinkedList<Connection> conns = new LinkedList<Connection>();
    //成员属性初始化
    static {
        try {
            Properties pro = new Properties();
            pro.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connPool.properties"));
            driverClass = pro.getProperty("driver");
            url = pro.getProperty("url");
            userName = pro.getProperty("userName");
            password = pro.getProperty("password");
            try {
                initCount = new Integer(pro.getProperty("initCount"));
            }catch (Exception e){

            }
            try {
                minCount = new Integer(pro.getProperty("minCount"));
            }catch (Exception e){

            }
            try {
                maxCount = new Integer(pro.getProperty("maxCount"));
            }catch (Exception e){

            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 初始化连接
     */
    private void init(){
        //循环的给集合中添加初始化个数的连接
        for(int i=0;i<initCount;i++){
            boolean flag = conns.add(createConnection());
            if(flag){
                //添加成功，连接数加1
                count++;
            }
        }
        System.out.println("连接池初始化完毕，连接数量："+count);
        getCount();
    }

    /**
     * 创建一个可用的数据库连接
     */
    private Connection createConnection(){
        try{
            Class.forName(driverClass);
            return DriverManager.getConnection(url,userName,password);
        }catch (Exception e){
            throw new RuntimeException("连接创建失败："+e.getMessage());
        }
    }

    /**
     * 返回连接池中的连接数量
     */
    public int getCount(){
        System.out.println("池中数量："+count);
        return count;
    }

    /**
     * 池中自动添加连接
     */
    private synchronized void addAuto(){
        if(count==maxCount){
            throw new RuntimeException("池中连接数量已达到最大值");
        }
        //增长步长为3
        for(int i=0;i<3;i++){
            if(count==maxCount){
                break;
            }
            conns.add(createConnection());
            count++;
        }
    }

    /**
     * 池中连接自动缩减
     */
    private synchronized void subAuto(){
        if(conns.size()>minCount){
            try {
                //从池中获取一个连接并关闭
                Connection conn = conns.removeFirst();
                conn.close();
                conn=null;
                count--;
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取可用连接
     */
    public Connection getConnection(){
        /**
         * 可使用递归
         * 同时二次校验
         */
        while(true) {
            //判断池中是否有可用连接
            if (conns.size() > 0) {
                return conns.removeFirst();
            }
            //判断总链接数是否达到上限
            if (count < maxCount) {
                addAuto();
            }
            //如果池中连接已达上限，就等待
            if(count==maxCount){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 归还连接操作
     */
    public void close(Connection conn){
        conns.add(conn);
        subAuto();
    }
}
